#pragma once
#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Watcher.hpp>
#include "log.hpp"

//向etcd注册服务
class Registry {
private:
    etcd::Client _client;
    etcd::KeepAlive _keep_alive;
    uint64_t _lease_id;
public:
    using ptr = std::shared_ptr<Registry>;
    Registry(const std::string& addr, int ttl = 3)
        : _client(addr)
        , _keep_alive(_client, ttl)
        , _lease_id(_keep_alive.Lease()) {}


    ~Registry() {
        _keep_alive.Cancel();
    }



    bool registry(const std::string& key, const std::string& value) {
        auto resp = _client.add(key, value, _lease_id).get();
        if (!resp.is_ok()) {
            LOG_ERROR("注册数据失败: {}", resp.error_message());
            return false;
        }
        return true;
    }
};



class Discovery {
public:
    using ptr = std::shared_ptr<Discovery>;
    using NotifyCallback = std::function<void(const std::string&, const std::string&)>;
private:
    etcd::Client _client;
    etcd::Watcher _watcher;
    NotifyCallback _put_cb;
    NotifyCallback _del_cb;

    
private:
    //键值对发生改变后的回调
    void WatchCallback(const etcd::Response& resp) {
        if(!resp.is_ok()) {
            LOG_ERROR("收到错误事件通知: {}", resp.error_message());
            return;
        }
        for(const etcd::Event& ev: resp.events()) {
            if(ev.event_type() == etcd::Event::EventType::PUT) {
                LOG_DEBUG("新增服务: {} - {}", ev.kv().key(), ev.kv().as_string());
                if(_put_cb) {
                    _put_cb(ev.kv().key(), ev.kv().as_string());
                }
            }
            else if(ev.event_type() == etcd::Event::EventType::DELETE_) {
                LOG_DEBUG("下线服务: {} - {}", ev.prev_kv().key(), ev.prev_kv().as_string());
                if(_del_cb) {
                    _del_cb(ev.prev_kv().key(), ev.prev_kv().as_string());
                }
            }
            else {
                LOG_WARN("收到未知事件类型: {}", static_cast<int>(ev.event_type()));
            }
        }
    }


public:
    Discovery(const std::string& addr            // http://127.0.0.1:2379
            , const std::string& basedir
            , const NotifyCallback& put_cb
            , const NotifyCallback& del_cb)
        : _client(addr)
        , _watcher(_client, basedir, std::bind(&Discovery::WatchCallback, this, std::placeholders::_1), true)
        , _put_cb(put_cb)
        , _del_cb(del_cb) {
        auto resp = _client.ls(basedir).get();
        if(!resp.is_ok()) {
            LOG_ERROR("获取服务信息数据失败：{}", resp.error_message());
            return;
        }   
        int sz = resp.keys().size();
        for(int i = 0; i < sz; ++i) {
            LOG_DEBUG("已注册服务: {} - {}", resp.key(i), resp.value(i).as_string());
            // resp.key(i);
            // resp.value(i).as_string();
            if(_put_cb) {
                _put_cb(resp.key(i), resp.value(i).as_string());
            }
        }
    }
};